
package com.chongchong.core.mp.base;

import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chongchong.core.mp.annotation.*;
import com.chongchong.core.mp.dao.BaseDaoMapper;
import com.chongchong.core.mp.exception.InvalidDataFieldException;
import com.chongchong.core.mp.object.*;
import com.chongchong.core.secure.SysUser;
import com.chongchong.core.secure.utils.SecureUtil;
import com.chongchong.core.tool.api.R;
import com.chongchong.core.tool.constant.AggregationType;
import com.chongchong.core.tool.constant.SysConstant;
import com.chongchong.core.tool.context.ApplicationContextHolder;
import com.chongchong.core.tool.utils.AopTargetUtil;
import com.chongchong.core.tool.utils.DateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.function.Function;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
 * 业务封装基础类
 *
 * @param <M> mapper
 * @param <T> model
 * @author Chill
 */
@Validated
public abstract class BaseServiceImpl<M extends BaseDaoMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> {

	/**
	 * 当前Service关联的主Model实体对象的Class。
	 */
	protected final Class<T> modelClass;
	/**
	 * 当前Service关联的主Model实体对象的实际表名称。
	 */
	protected final String tableName;
	/**
	 * 当前Service关联的主Model对象主键字段名称。
	 */
	protected String idFieldName;
	/**
	 * 当前Service关联的主数据表中主键列名称。
	 */
	protected String idColumnName;
	/**
	 * 当前Service关联的主Model对象逻辑删除字段名称。
	 */
	protected String deletedFlagFieldName;
	/**
	 * 当前Service关联的主数据表中逻辑删除字段名称。
	 */
	protected String deletedFlagColumnName;

	/**
	 * 当前Service关联的主Model对象的所有字典关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationDictStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有常量字典关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationConstDictStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有一对一关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationOneToOneStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有一对多关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationOneToManyStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有多对多关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationManyToManyStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有一对多聚AopTargetUtil合关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationOneToManyAggrStructList = new LinkedList<>();
	/**
	 * 当前Service关联的主Model对象的所有多对多聚合关联的结构列表，该字段在系统启动阶段一次性预加载，提升运行时效率。
	 */
	private final List<RelationStruct> relationManyToManyAggrStructList = new LinkedList<>();

	private static final String GROUPED_KEY = "groupedKey";
	private static final String AGGREGATED_VALUE = "aggregatedValue";
	private static final String AND_OP = " AND ";


	/**
	 * 基础表的实体对象及表信息。
	 */

	public BaseServiceImpl() {
		modelClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
		this.tableName = modelClass.getAnnotation(TableName.class).value();
		Field[] fields = ReflectUtil.getFields(modelClass);
		for (Field field : fields) {
			initializeField(field);
		}
	}

	private void initializeField(Field field) {
		if (idFieldName == null && null != field.getAnnotation(TableId.class)) {
			idFieldName = field.getName();
			TableId c = field.getAnnotation(TableId.class);
			idColumnName = c == null ? idFieldName : c.value();
		}
	}

	/**
	 * 仅仅在spring boot 启动后的监听器事件中调用，缓存所有service的关联关系，加速后续的数据绑定效率。
	 */
	@Override
	public void loadRelationStruct() {
		Field[] fields = ReflectUtil.getFields(modelClass);
		if(modelClass.getName().indexOf("OnlineDatasourceRelation") > -1) {
			System.out.println(modelClass.getName());
		}
		for (Field f : fields) {
			initializeRelationDictStruct(f);
			initializeRelationStruct(f);
			initializeRelationAggregationStruct(f);
		}
	}

	@SuppressWarnings("unchecked")
	private void initializeRelationDictStruct(Field f) {
		RelationConstDict relationConstDict = f.getAnnotation(RelationConstDict.class);
		if (relationConstDict != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationConstDict.masterIdField());
			Field dictMapField = ReflectUtil.getField(relationConstDict.constantDictClass(), "DICT_MAP");
			relationStruct.dictMap = (Map<Object, String>) ReflectUtil.getFieldValue(modelClass, dictMapField);
			relationConstDictStructList.add(relationStruct);
			return;
		}
		RelationDict relationDict = f.getAnnotation(RelationDict.class);
		if (relationDict != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationDict.masterIdField());
			relationStruct.relationDict = relationDict;
			if (StringUtils.isNotBlank(relationDict.equalOneToOneRelationField())) {
				relationStruct.equalOneToOneRelationField =
					ReflectUtil.getField(modelClass, relationDict.equalOneToOneRelationField());
			}
			if (StringUtils.isNotBlank(relationDict.slaveServiceName())) {
				relationStruct.service = ApplicationContextHolder.getBean(
					StringUtils.uncapitalize(relationDict.slaveServiceName()));
			} else {
				relationStruct.service = (BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>)
					ApplicationContextHolder.getBean(relationDict.slaveServiceClass());
			}
			relationDictStructList.add(relationStruct);
		}
	}

	@SuppressWarnings("unchecked")
	private void initializeRelationStruct(Field f) {
		RelationOneToOne relationOneToOne = f.getAnnotation(RelationOneToOne.class);
		if (relationOneToOne != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToOne.masterIdField());
			relationStruct.relationOneToOne = relationOneToOne;
			if (StringUtils.isNotBlank(relationOneToOne.slaveServiceName())) {
				relationStruct.service = ApplicationContextHolder.getBean(
					StringUtils.uncapitalize(relationOneToOne.slaveServiceName()));
			} else {
				relationStruct.service = (BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>)
					ApplicationContextHolder.getBean(relationOneToOne.slaveServiceClass());
			}
			relationOneToOneStructList.add(relationStruct);
			return;
		}
		RelationOneToMany relationOneToMany = f.getAnnotation(RelationOneToMany.class);
		if (relationOneToMany != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToMany.masterIdField());
			relationStruct.relationOneToMany = relationOneToMany;
			if (StringUtils.isNotBlank(relationOneToMany.slaveServiceName())) {
				relationStruct.service = ApplicationContextHolder.getBean(
					StringUtils.uncapitalize(relationOneToMany.slaveServiceName()));
			} else {
				relationStruct.service = (BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>)
					ApplicationContextHolder.getBean(relationOneToMany.slaveServiceClass());
			}
			relationOneToManyStructList.add(relationStruct);
			return;
		}
		RelationManyToMany relationManyToMany = f.getAnnotation(RelationManyToMany.class);
		if (relationManyToMany != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToMany.relationMasterIdField());
			relationStruct.relationManyToMany = relationManyToMany;
			relationStruct.manyToManyMapper = ApplicationContextHolder.getBean(
				StringUtils.uncapitalize(relationManyToMany.relationMapperName()));
			relationManyToManyStructList.add(relationStruct);
		}
	}

	@SuppressWarnings("unchecked")
	private void initializeRelationAggregationStruct(Field f) {
		RelationOneToManyAggregation relationOneToManyAggregation = f.getAnnotation(RelationOneToManyAggregation.class);
		if (relationOneToManyAggregation != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToManyAggregation.masterIdField());
			relationStruct.relationOneToManyAggregation = relationOneToManyAggregation;
			if (StringUtils.isNotBlank(relationOneToManyAggregation.slaveServiceName())) {
				relationStruct.service = ApplicationContextHolder.getBean(
					StringUtils.uncapitalize(relationOneToManyAggregation.slaveServiceName()));
			} else {
				relationStruct.service = (BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>)
					ApplicationContextHolder.getBean(relationOneToManyAggregation.slaveServiceClass());
			}
			relationOneToManyAggrStructList.add(relationStruct);
			return;
		}
		RelationManyToManyAggregation relationManyToManyAggregation = f.getAnnotation(RelationManyToManyAggregation.class);
		if (relationManyToManyAggregation != null) {
			RelationStruct relationStruct = new RelationStruct();
			relationStruct.relationField = f;
			relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToManyAggregation.masterIdField());
			relationStruct.relationManyToManyAggregation = relationManyToManyAggregation;
			if (StringUtils.isNotBlank(relationManyToManyAggregation.slaveServiceName())) {
				relationStruct.service = ApplicationContextHolder.getBean(
					StringUtils.uncapitalize(relationManyToManyAggregation.slaveServiceName()));
			} else {
				relationStruct.service = (BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>)
					ApplicationContextHolder.getBean(relationManyToManyAggregation.slaveServiceClass());
			}
			relationManyToManyAggrStructList.add(relationStruct);
		}
	}

	@Override
	public boolean save(T entity) {
		SysUser user = SecureUtil.getUser();
		if (user != null) {
			entity.setCreateUserId(user.getUserId());
			entity.setUpdateUserId(user.getUserId());
		}
		Date now = DateUtil.now();
		entity.setCreateTime(now);
		entity.setUpdateTime(now);
		if (entity.getStatus() == null) {
			entity.setStatus(SysConstant.STATUS_NORMAL);
		}
		entity.setIsDeleted(SysConstant.NOT_DELETED);
		return super.save(entity);
	}

	@Override
	public boolean updateById(T entity) {
		SysUser user = SecureUtil.getUser();
		if (user != null) {
			entity.setUpdateUserId(user.getUserId());
		}
		entity.setUpdateTime(DateUtil.now());
		return super.updateById(entity);
	}

	@Override
	public boolean deleteLogic(@NotEmpty List<Long> ids) {
		return super.removeByIds(ids);
	}

	/**
	 * 判断当前对象的关联字段数据是否需要被验证，如果原有对象为null，表示新对象第一次插入，则必须验证。
	 *
	 * @param object         新对象。
	 * @param originalObject 原有对象。
	 * @param fieldGetter    获取需要验证字段的函数对象。
	 * @param <K>            需要验证字段的类型。
	 * @return 需要关联验证返回true，否则false。
	 */
	protected <K> boolean needToVerify(T object, T originalObject, Function<T, K> fieldGetter) {
		if (object == null) {
			return false;
		}
		K data = fieldGetter.apply(object);
		if (data == null) {
			return false;
		}
		if (data instanceof String) {
			String stringData = (String) data;
			if (stringData.length() == 0) {
				return false;
			}
		}
		if (originalObject == null) {
			return true;
		}
		K originalData = fieldGetter.apply(originalObject);
		return !data.equals(originalData);
	}

	@Override
	public R verifyRelatedData(T data, T originalData) {
		return R.success("");
	}

	/**
	 * 获取主表的查询结果，以及主表关联的字典数据和一对一从表数据，以及一对一从表的字典数据。
	 *
	 * @param id             主表主键Id。
	 * @param relationParam  实体对象数据组装的参数构建器。
	 * @return 查询结果对象。
	 */
	@Override
	public T getByIdWithRelation(Long id, MyRelationParam relationParam) {
		T dataObject = this.getById(id);
		this.buildRelationForData(dataObject, relationParam);
		return dataObject;
	}

	/**
	 * 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param dataObject    主表实体对象。数据集成将直接作用于该对象。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param <K>           实体对象类型。
	 */
	@Override
	public <K extends T> void buildRelationForData(T dataObject, MyRelationParam relationParam) {
		this.buildRelationForData(dataObject, relationParam, null);
	}

	/**
	 * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param dataObject    主表实体对象。数据集成将直接作用于该对象。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 * @param <K>           实体对象类型。
	 */
	@Override
	public <K extends T> void buildRelationForData(T dataObject, MyRelationParam relationParam, Set<String> ignoreFields) {
		if (dataObject == null || relationParam == null) {
			return;
		}
		boolean dataFilterValue = GlobalThreadLocal.setDataFilter(false);
		try {
			// 集成本地一对一和字段级别的数据关联。
			boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict();
			if (buildOneToOne) {
				this.buildOneToOneForData(dataObject, relationParam.isBuildOneToOneWithDict(), ignoreFields);
			}
			// 集成一对多关联
			if (relationParam.isBuildOneToMany()) {
				this.buildOneToManyForData(dataObject, ignoreFields);
			}
			if (relationParam.isBuildDict()) {
				// 构建常量字典关联关系
				this.buildConstDictForData(dataObject, ignoreFields);
				// 构建本地数据字典关联关系。
				this.buildDictForData(dataObject, buildOneToOne, ignoreFields);
			}
			// 组装本地聚合计算关联数据
			if (relationParam.isBuildRelationAggregation()) {
				// 开始处理多对多场景。
				buildManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields);
				// 构建一对多场景
				buildOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields);
			}
			if (relationParam.isBuildRelationManyToMany()) {
				this.buildRelationManyToMany(dataObject, ignoreFields);
			}
		} finally {
			GlobalThreadLocal.setDataFilter(dataFilterValue);
		}
	}

	/**
	 * 为实体对象数据集成本地一对一关联数据。
	 *
	 * @param dataObject   实体对象。
	 * @param withDict     关联从表数据后，是否把从表的字典数据也一起关联了。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToOneForData(T dataObject, boolean withDict, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToOneStructList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationOneToOneStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			if (id != null) {
				BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> relationService = relationStruct.service;
				Object relationObject = relationService.getOne(relationStruct.relationOneToOne.slaveIdField(), id);
				ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject);
				// 仅仅当需要加载从表字典关联时，才去加载。
				if (withDict && relationStruct.relationOneToOne.loadSlaveDict() && relationObject != null) {
					@SuppressWarnings("unchecked")
					BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> proxyTarget =
						(BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>) AopTargetUtil.getTarget(relationService);
					// 关联本地字典
					proxyTarget.buildDictForData((BaseEntity) relationObject, false, ignoreFields);
					// 关联常量字典
					proxyTarget.buildConstDictForData((BaseEntity) relationObject, ignoreFields);
				}
			}
		}
	}

	/**
	 * 返回符合 filterField = filterValue 条件的一条数据。
	 *
	 * @param filterField 过滤的Java字段。
	 * @param filterValue 过滤的Java字段值。
	 * @return 查询后的数据对象。
	 */
	@SuppressWarnings("unchecked")
	@Override
	public T getOne(String filterField, Object filterValue) {
		if (filterField.equals(idFieldName)) {
			return this.getById((Long) filterValue);
		}
		String columnName = this.safeMapToColumnName(filterField);
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>().eq(columnName, filterValue);
		return this.getOne(queryWrapper);
	}


	/**
	 * 因为Mybatis Plus中QueryWrapper的条件方法都要求传入数据表字段名，因此提供该函数将
	 * Java实体对象的字段名转换为数据表字段名，如果不存在会抛出异常。
	 * 另外在MyModelUtil.mapToColumnName有一级缓存，对于查询过的对象字段都会放到缓存中，
	 * 下次映射转换的时候，会直接从缓存获取。
	 *
	 * @param fieldName Java实体对象的字段名。
	 * @return 对应的数据表字段名。
	 */
	protected String safeMapToColumnName(String fieldName) {
		String columnName = MyModelUtil.mapToColumnName(fieldName, modelClass);
		if (columnName == null) {
			throw new InvalidDataFieldException(modelClass.getSimpleName(), fieldName);
		}
		return columnName;
	}

	/**
	 * 为实体对象数据集成本地数据字典关联数据。
	 *
	 * @param dataObject       实体对象。
	 * @param hasBuiltOneToOne 性能优化参数。如果该值为true，同时注解参数RelationDict.equalOneToOneRelationField
	 *                         不为空，则直接从已经完成一对一数据关联的从表对象中获取数据，减少一次数据库交互。
	 * @param ignoreFields     该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildDictForData(T dataObject, boolean hasBuiltOneToOne, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationDictStructList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationDictStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object relationObject = null;
			if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) {
				relationObject = ReflectUtil.getFieldValue(dataObject, relationStruct.equalOneToOneRelationField);
			} else {
				Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
				if (id != null) {
					relationObject = relationStruct.service.getOne(relationStruct.relationDict.slaveIdField(), id);
				}
			}
			MyModelUtil.makeDictRelation(
				modelClass, dataObject, relationObject, relationStruct.relationField.getName());
		}
	}

	/**
	 * 为参数实体对象数据集成本地静态字典关联数据。
	 *
	 * @param dataObject   实体对象。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildConstDictForData(T dataObject, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationConstDictStructList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationConstDictStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			if (id != null) {
				String name = relationStruct.dictMap.get(id);
				if (name != null) {
					Map<String, Object> dictMap = new HashMap<>(2);
					dictMap.put("id", id);
					dictMap.put("name", name);
					ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap);
				}
			}
		}
	}

	/**
	 * 为实体对象数据集成本地一对多关联数据。
	 *
	 * @param dataObject   实体对象。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToManyForData(T dataObject, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyStructList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationOneToManyStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			if (id != null) {
				BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> relationService = relationStruct.service;
				Set<Object> masterIdSet = new HashSet<>(1);
				masterIdSet.add(id);
				List<BaseEntity> relationObject = relationService.getInList(
					relationStruct.relationOneToMany.slaveIdField(), masterIdSet);
				ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject);
			}
		}
	}

	/**
	 * 返回符合主键 in (idValues) 条件的所有数据。
	 *
	 * @param idValues 主键值集合。
	 * @return 检索后的数据列表。
	 */
	@Override
	public List<T> getInList(Set<Object> idValues) {
		return this.getInList(idFieldName, idValues, null);
	}

	/**
	 * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。
	 *
	 * @param inFilterField  参与(In-list)过滤的Java字段。
	 * @param inFilterValues 参与(In-list)过滤的Java字段值集合。
	 * @return 检索后的数据列表。
	 */
	@Override
	public List<T> getInList(String inFilterField, Set<Object> inFilterValues) {
		return this.getInList(inFilterField, inFilterValues, null);
	}

	/**
	 * 返回符合 inFilterField in (inFilterValues) 条件的所有数据，并根据orderBy字段排序。
	 *
	 * @param inFilterField  参与(In-list)过滤的Java字段。
	 * @param inFilterValues 参与(In-list)过滤的Java字段值集合。
	 * @param orderBy        排序字段。
	 * @return 检索后的数据列表。
	 */
	@Override
	public List<T> getInList(String inFilterField, Set<Object> inFilterValues, String orderBy) {
		if (CollectionUtils.isEmpty(inFilterValues)) {
			return new LinkedList<>();
		}
		String column = this.safeMapToColumnName(inFilterField);
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>().in(column, inFilterValues);
		if (StringUtils.isNotBlank(orderBy)) {
			queryWrapper.last(orderBy);
		}
		return super.getBaseMapper().selectList(queryWrapper);
	}

	/**
	 * 根据实体对象和过滤条件，集成本地多对多关联聚合计算数据。
	 *
	 * @param dataObject      实体对象。
	 * @param criteriaListMap 过滤参数。key为主表字段名称，value是过滤条件列表。
	 * @param ignoreFields    该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildManyToManyAggregationForData(
		T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyAggrStructList)) {
			return;
		}
		if (criteriaListMap == null) {
			criteriaListMap = new HashMap<>(relationManyToManyAggrStructList.size());
		}
		for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			if (masterIdValue != null) {
				BasicAggregationRelationInfo basicRelationInfo =
					this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap);
				// 组装过滤条件
				String whereClause = this.makeManyToManyWhereClause(
					relationStruct, masterIdValue, basicRelationInfo, criteriaListMap);
				StringBuilder tableNames = new StringBuilder(64);
				tableNames.append(basicRelationInfo.relationTable);
				if (!basicRelationInfo.onlySelectRelationTable) {
					tableNames.append(", ").append(basicRelationInfo.slaveTable);
				}
				List<Map<String, Object>> aggregationMapList =
					super.getBaseMapper().getGroupedListByCondition(tableNames.toString(),
						basicRelationInfo.selectList, whereClause, basicRelationInfo.groupBy);
				// 将查询后的结果回填到主表数据中。
				if (CollectionUtils.isNotEmpty(aggregationMapList)) {
					Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
					if (value != null) {
						ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
					}
				}
			}
		}
	}

	private BasicAggregationRelationInfo parseBasicAggregationRelationInfo(
		RelationStruct relationStruct, Map<String, List<MyWhereCriteria>> criteriaListMap) {
		RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation;
		BasicAggregationRelationInfo relationInfo = new BasicAggregationRelationInfo();
		// 提取关联中用到的各种字段和表数据。
		relationInfo.slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass());
		relationInfo.relationTable = MyModelUtil.mapToTableName(relation.relationModelClass());
		relationInfo.relationMasterColumn =
			MyModelUtil.mapToColumnName(relation.relationMasterIdField(), relation.relationModelClass());
		relationInfo.relationSlaveColumn =
			MyModelUtil.mapToColumnName(relation.relationSlaveIdField(), relation.relationModelClass());
		relationInfo.slaveColumn = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass());
		// 判断是否只需要关联中间表即可，从而提升查询统计的效率。
		// 1. 统计字段为中间表字段。2. 自定义过滤条件中没有基于从表字段的过滤条件。
		relationInfo.onlySelectRelationTable =
			relation.aggregationModelClass().equals(relation.relationModelClass());
		if (relationInfo.onlySelectRelationTable && MapUtils.isNotEmpty(criteriaListMap)) {
			List<MyWhereCriteria> criteriaList =
				criteriaListMap.get(relationStruct.relationField.getName());
			if (CollectionUtils.isNotEmpty(criteriaList)) {
				for (MyWhereCriteria whereCriteria : criteriaList) {
					if (whereCriteria.getModelClazz().equals(relation.slaveModelClass())) {
						relationInfo.onlySelectRelationTable = false;
						break;
					}
				}
			}
		}
		String aggregationTable = relation.aggregationModelClass().equals(relation.relationModelClass())
			? relationInfo.relationTable : relationInfo.slaveTable;
		Tuple2<String, String> selectAndGroupByTuple = makeSelectListAndGroupByClause(
			relationInfo.relationTable, relationInfo.relationMasterColumn, relation.aggregationModelClass(),
			aggregationTable, relation.aggregationField(), relation.aggregationType());
		relationInfo.selectList = selectAndGroupByTuple.getFirst();
		relationInfo.groupBy = selectAndGroupByTuple.getSecond();
		return relationInfo;
	}

	private Tuple2<String, String> makeSelectListAndGroupByClause(
		String groupTableName,
		String groupColumnName,
		Class<?> aggregationModel,
		String aggregationTableName,
		String aggregationField,
		Integer aggregationType) {
		if (!AggregationType.isValid(aggregationType)) {
			throw new IllegalArgumentException("Invalid AggregationType Value ["
				+ aggregationType + "] in Model [" + aggregationModel.getName() + "].");
		}
		String aggregationFunc = AggregationType.getAggregationFunction(aggregationType);
		String aggregationColumn = MyModelUtil.mapToColumnName(aggregationField, aggregationModel);
		if (StringUtils.isBlank(aggregationColumn)) {
			throw new IllegalArgumentException("Invalid AggregationField ["
				+ aggregationField + "] in Model [" + aggregationModel.getName() + "].");
		}
		// 构建Select List
		// 如：r_table.master_id groupedKey, SUM(r_table.aggr_column) aggregated_value
		StringBuilder groupedSelectList = new StringBuilder(128);
		groupedSelectList.append(groupTableName)
			.append(".")
			.append(groupColumnName)
			.append(" ")
			.append(GROUPED_KEY)
			.append(", ")
			.append(aggregationFunc)
			.append("(")
			.append(aggregationTableName)
			.append(".")
			.append(aggregationColumn)
			.append(") ")
			.append(AGGREGATED_VALUE)
			.append(" ");
		StringBuilder groupBy = new StringBuilder(64);
		groupBy.append(groupTableName).append(".").append(groupColumnName);
		return new Tuple2<>(groupedSelectList.toString(), groupBy.toString());
	}

	private String makeManyToManyWhereClause(
		RelationStruct relationStruct,
		Object masterIdValue,
		BasicAggregationRelationInfo basicRelationInfo,
		Map<String, List<MyWhereCriteria>> criteriaListMap) {
		StringBuilder whereClause = new StringBuilder(256);
		whereClause.append(basicRelationInfo.relationTable)
			.append(".").append(basicRelationInfo.relationMasterColumn);
		if (masterIdValue instanceof Number) {
			whereClause.append(" = ").append(masterIdValue);
		} else {
			whereClause.append(" = '").append(masterIdValue).append("'");
		}
		// 如果需要从表聚合计算或参与过滤，则需要把中间表和从表之间的关联条件加上。
		if (!basicRelationInfo.onlySelectRelationTable) {
			whereClause.append(AND_OP)
				.append(basicRelationInfo.relationTable)
				.append(".")
				.append(basicRelationInfo.relationSlaveColumn)
				.append(" = ")
				.append(basicRelationInfo.slaveTable)
				.append(".")
				.append(basicRelationInfo.slaveColumn);
		}
		List<MyWhereCriteria> criteriaList = criteriaListMap.get(relationStruct.relationField.getName());
		if (criteriaList == null) {
			criteriaList = new LinkedList<>();
		}
		if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) {
			MyWhereCriteria deleteFilter = new MyWhereCriteria();
			deleteFilter.setCriteria(
				relationStruct.relationManyToManyAggregation.slaveModelClass(),
				relationStruct.service.deletedFlagFieldName,
				MyWhereCriteria.OPERATOR_EQUAL,
				SysConstant.STATUS_NORMAL);
			criteriaList.add(deleteFilter);
		}
		if (CollectionUtils.isNotEmpty(criteriaList)) {
			String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList);
			whereClause.append(AND_OP).append(criteriaString);
		}
		return whereClause.toString();
	}

	/**
	 * 根据指定的显示字段列表、过滤条件字符串和分组字符串，返回聚合计算后的查询结果。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param selectFields 选择的字段列表，多个字段逗号分隔。
	 *                     NOTE: 如果数据表字段和Java对象字段名字不同，Java对象字段应该以别名的形式出现。
	 *                     如: table_column_name modelFieldName。否则无法被反射回Bean对象。
	 * @param whereClause  SQL常量形式的条件从句。
	 * @param groupBy      SQL常量形式分组字段列表，逗号分隔。
	 * @return 聚合计算后的数据结果集。
	 */
	@Override
	public List<Map<String, Object>> getGroupedListByCondition(
		String selectFields, String whereClause, String groupBy) {
		return super.getBaseMapper().getGroupedListByCondition(tableName, selectFields, whereClause, groupBy);
	}

	/**
	 * 根据指定的显示字段列表、过滤条件字符串和排序字符串，返回查询结果。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param selectList  选择的Java字段列表。如果为空表示返回全部字段。
	 * @param filter      过滤对象。
	 * @param whereClause SQL常量形式的条件从句。
	 * @param orderBy     SQL常量形式排序字段列表，逗号分隔。
	 * @return 查询结果。
	 */
	@Override
	public List<T> getListByCondition(List<String> selectList, T filter, String whereClause, String orderBy) {
		QueryWrapper<T> queryWrapper = new QueryWrapper<>(filter);
		if (CollectionUtils.isNotEmpty(selectList)) {
			String[] columns = new String[selectList.size()];
			for (int i = 0; i < selectList.size(); i++) {
				columns[i] = this.safeMapToColumnName(selectList.get(i));
			}
			queryWrapper.select(columns);
		}
		if (StringUtils.isNotBlank(whereClause)) {
			queryWrapper.apply(whereClause);
		}
		if (StringUtils.isNotBlank(orderBy)) {
			queryWrapper.last(" ORDER BY " + orderBy);
		}
		return super.getBaseMapper().selectList(queryWrapper);
	}

	/**
	 * 缺省实现返回null，在进行一对多和多对多聚合计算时，没有额外的自定义过滤条件。如有需要，需子类自行实现。
	 *
	 * @return 自定义过滤条件列表。
	 */
	protected Map<String, List<MyWhereCriteria>> buildAggregationAdditionalWhereCriteria() {
		return null;
	}

	/**
	 * 用指定过滤条件，计算记录数量。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param whereClause SQL常量形式的条件从句。
	 * @return 返回过滤后的数据数量。
	 */
	@Override
	public Integer getCountByCondition(String whereClause) {
		return super.getBaseMapper().getCountByCondition(this.tableName, whereClause);
	}

	/**
	 * 根据实体对象和过滤条件，集成本地一对多关联聚合计算数据。
	 *
	 * @param dataObject      实体对象。
	 * @param criteriaListMap 过滤参数。key为主表字段名称，value是过滤条件列表。
	 * @param ignoreFields    该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToManyAggregationForData(
		T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyAggrStructList)) {
			return;
		}
		if (criteriaListMap == null) {
			criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size());
		}
		for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			if (masterIdValue != null) {
				RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation;
				String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass());
				String slaveColumnName =
					MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass());
				Tuple2<String, String> selectAndGroupByTuple = makeSelectListAndGroupByClause(
					slaveTable, slaveColumnName, relation.slaveModelClass(),
					slaveTable, relation.aggregationField(), relation.aggregationType());
				String selectList = selectAndGroupByTuple.getFirst();
				String groupBy = selectAndGroupByTuple.getSecond();
				String whereClause = this.makeOneToManyWhereClause(
					relationStruct, masterIdValue, slaveColumnName, criteriaListMap);
				// 获取分组聚合计算结果
				List<Map<String, Object>> aggregationMapList =
					super.getBaseMapper().getGroupedListByCondition(slaveTable, selectList, whereClause, groupBy);
				// 将计算结果回填到主表关联字段
				if (CollectionUtils.isNotEmpty(aggregationMapList)) {
					Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
					if (value != null) {
						ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
					}
				}
			}
		}
	}

	/**
	 * 集成主表和多对多中间表之间的关联关系。
	 *
	 * @param dataObject   关联后的主表数据对象。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildRelationManyToMany(T dataObject, Set<String> ignoreFields) {
		if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyStructList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationManyToManyStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
			String masterIdColumn = this.safeMapToColumnName(relationStruct.masterIdField.getName());
			Map<String, Object> filterMap = new HashMap<>(1);
			filterMap.put(masterIdColumn, masterIdValue);
			List<?> manyToManyList = relationStruct.manyToManyMapper.selectByMap(filterMap);
			ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, manyToManyList);
		}
	}

	private String makeOneToManyWhereClause(
		RelationStruct relationStruct,
		Object masterIdValue,
		String slaveColumnName,
		Map<String, List<MyWhereCriteria>> criteriaListMap) {
		StringBuilder whereClause = new StringBuilder(64);
		if (masterIdValue instanceof Number) {
			whereClause.append(slaveColumnName).append(" = ").append(masterIdValue);
		} else {
			whereClause.append(slaveColumnName).append(" = '").append(masterIdValue).append("'");
		}
		List<MyWhereCriteria> criteriaList = criteriaListMap.get(relationStruct.relationField.getName());
		if (criteriaList == null) {
			criteriaList = new LinkedList<>();
		}
		if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) {
			MyWhereCriteria deleteFilter = new MyWhereCriteria();
			deleteFilter.setCriteria(
				relationStruct.relationOneToManyAggregation.slaveModelClass(),
				relationStruct.service.deletedFlagFieldName,
				MyWhereCriteria.OPERATOR_EQUAL,
				SysConstant.STATUS_NORMAL);
			criteriaList.add(deleteFilter);
		}
		if (CollectionUtils.isNotEmpty(criteriaList)) {
			String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList);
			whereClause.append(AND_OP).append(criteriaString);
		}
		return whereClause.toString();
	}

	/**
	 * 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 */
	@Override
	public void buildRelationForDataList(List<T> resultList, MyRelationParam relationParam) {
		this.buildRelationForDataList(resultList, relationParam, null);
	}

	/**
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	@Override
	public void buildRelationForDataList(
		List<T> resultList, MyRelationParam relationParam, Set<String> ignoreFields) {
		if (relationParam == null || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		boolean dataFilterValue = GlobalThreadLocal.setDataFilter(false);
		try {
			// 集成本地一对一和字段级别的数据关联。
			boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict();
			// 这里集成一对一关联。
			if (buildOneToOne) {
				this.buildOneToOneForDataList(resultList, relationParam.isBuildOneToOneWithDict(), ignoreFields);
			}
			// 集成一对多关联
			if (relationParam.isBuildOneToMany()) {
				this.buildOneToManyForDataList(resultList, ignoreFields);
			}
			// 这里集成字典关联
			if (relationParam.isBuildDict()) {
				// 构建常量字典关联关系
				this.buildConstDictForDataList(resultList, ignoreFields);
				this.buildDictForDataList(resultList, buildOneToOne, ignoreFields);
			}
			// 组装本地聚合计算关联数据
			if (relationParam.isBuildRelationAggregation()) {
				// 处理多对多场景下，根据主表的结果，进行从表聚合数据的计算。
				this.buildManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields);
				// 处理多一多场景下，根据主表的结果，进行从表聚合数据的计算。
				this.buildOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields);
			}
		} finally {
			GlobalThreadLocal.setDataFilter(dataFilterValue);
		}
	}

	/**
	 * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询，批量导出没有分页机制，
	 * 因此在导出数据量较大的情况下，很容易给数据库的内存、CPU和IO带来较大的压力。而通过
	 * 我们的分批处理，可以极大的规避该问题的出现几率。调整batchSize的大小，也可以有效的
	 * 改善运行效率。
	 * 我们目前的处理机制是，先从主表取出所有符合条件的主表数据，这样可以避免分批处理时，
	 * 后面几批数据，因为skip过多而带来的效率问题。因为是单表过滤，不会给数据库带来过大的压力。
	 * 之后再在主表结果集数据上进行分批级联处理。
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param batchSize     每批集成的记录数量。小于等于0时将不做分批处理。
	 */
	@Override
	public void buildRelationForDataList(List<T> resultList, MyRelationParam relationParam, int batchSize) {
		this.buildRelationForDataList(resultList, relationParam, batchSize, null);
	}

	/**
	 * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询，批量导出没有分页机制，
	 * 因此在导出数据量较大的情况下，很容易给数据库的内存、CPU和IO带来较大的压力。而通过
	 * 我们的分批处理，可以极大的规避该问题的出现几率。调整batchSize的大小，也可以有效的
	 * 改善运行效率。
	 * 我们目前的处理机制是，先从主表取出所有符合条件的主表数据，这样可以避免分批处理时，
	 * 后面几批数据，因为skip过多而带来的效率问题。因为是单表过滤，不会给数据库带来过大的压力。
	 * 之后再在主表结果集数据上进行分批级联处理。
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param batchSize     每批集成的记录数量。小于等于0时将不做分批处理。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	@Override
	public void buildRelationForDataList(
		List<T> resultList, MyRelationParam relationParam, int batchSize, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(resultList)) {
			return;
		}
		if (batchSize <= 0) {
			this.buildRelationForDataList(resultList, relationParam);
			return;
		}
		int totalCount = resultList.size();
		int fromIndex = 0;
		int toIndex = Math.min(batchSize, totalCount);
		while (toIndex > fromIndex) {
			List<T> subResultList = resultList.subList(fromIndex, toIndex);
			this.buildRelationForDataList(subResultList, relationParam, ignoreFields);
			fromIndex = toIndex;
			toIndex = Math.min(batchSize + fromIndex, totalCount);
		}
	}

	/**
	 * 为实体对象参数列表数据集成本地一对一关联数据。
	 *
	 * @param resultList   实体对象数据列表。
	 * @param withDict     关联从表数据后，是否把从表的字典数据也一起关联了。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToOneForDataList(List<T> resultList, boolean withDict, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(this.relationOneToOneStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationOneToOneStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Set<Object> masterIdSet = resultList.stream()
				.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
				.filter(Objects::nonNull)
				.collect(toSet());
			// 从主表集合中，抽取主表关联字段的集合，再以in list形式去从表中查询。
			if (CollectionUtils.isNotEmpty(masterIdSet)) {
				BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> relationService = relationStruct.service;
				List<BaseEntity> relationList =
					relationService.getInList(relationStruct.relationOneToOne.slaveIdField(), masterIdSet);
				MyModelUtil.makeOneToOneRelation(
					modelClass, resultList, relationList, relationStruct.relationField.getName());
				// 仅仅当需要加载从表字典关联时，才去加载。
				if (withDict && relationStruct.relationOneToOne.loadSlaveDict()
					&& CollectionUtils.isNotEmpty(relationList)) {
					@SuppressWarnings("unchecked")
					BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> proxyTarget =
						(BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity>) AopTargetUtil.getTarget(relationService);
					// 关联本地字典。
					proxyTarget.buildDictForDataList(relationList, false, ignoreFields);
					// 关联常量字典
					proxyTarget.buildConstDictForDataList(relationList, ignoreFields);
				}
			}
		}
	}

	/**
	 * 为实体对象参数列表数据集成本地字典关联数据。
	 *
	 * @param resultList       实体对象数据列表。
	 * @param hasBuiltOneToOne 性能优化参数。如果该值为true，同时注解参数RelationDict.equalOneToOneRelationField
	 *                         不为空，则直接从已经完成一对一数据关联的从表对象中获取数据，减少一次数据库交互。
	 * @param ignoreFields     该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildDictForDataList(List<T> resultList, boolean hasBuiltOneToOne, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(this.relationDictStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationDictStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			List<Object> relationList = null;
			if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) {
				relationList = resultList.stream().map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.equalOneToOneRelationField))
					.filter(Objects::nonNull).collect(toList());
			} else {
				String slaveId = relationStruct.relationDict.slaveIdField();
				Set<Object> masterIdSet = resultList.stream()
					.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
					.filter(Objects::nonNull)
					.collect(toSet());
				if (CollectionUtils.isNotEmpty(masterIdSet)) {
					relationList = relationStruct.service.getInList(slaveId, masterIdSet).stream().collect(toList());
				}
			}
			MyModelUtil.makeDictRelation(
				modelClass, resultList, relationList, relationStruct.relationField.getName());
		}
	}

	/**
	 * 为实体对象参数列表数据集成本地静态字典关联数据。
	 *
	 * @param resultList   主表数据列表。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildConstDictForDataList(List<T> resultList, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(this.relationConstDictStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationConstDictStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			for (T dataObject : resultList) {
				Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
				if (id != null) {
					String name = relationStruct.dictMap.get(id);
					if (name != null) {
						Map<String, Object> dictMap = new HashMap<>(2);
						dictMap.put("id", id);
						dictMap.put("name", name);
						ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap);
					}
				}
			}
		}
	}

	/**
	 * 为实体对象参数列表数据集成本地一对多关联数据。
	 *
	 * @param resultList   实体对象数据列表。
	 * @param ignoreFields 该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToManyForDataList(List<T> resultList, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(this.relationOneToManyStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		for (RelationStruct relationStruct : this.relationOneToManyStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Set<Object> masterIdSet = resultList.stream()
				.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
				.filter(Objects::nonNull)
				.collect(toSet());
			// 从主表集合中，抽取主表关联字段的集合，再以in list形式去从表中查询。
			if (CollectionUtils.isNotEmpty(masterIdSet)) {
				BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> relationService = relationStruct.service;
				List<BaseEntity> relationList = relationService.getInList(relationStruct.relationOneToMany.slaveIdField(), masterIdSet);
				MyModelUtil.makeOneToManyRelation( modelClass, resultList, relationList, relationStruct.relationField.getName());
			}
		}
	}

	/**
	 * 根据实体对象参数列表和过滤条件，集成本地多对多关联聚合计算数据。
	 *
	 * @param resultList      实体对象数据列表。
	 * @param criteriaListMap 过滤参数。key为主表字段名称，value是过滤条件列表。
	 * @param ignoreFields    该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildManyToManyAggregationForDataList(
		List<T> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
		if (CollectionUtils.isEmpty(this.relationManyToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		if (criteriaListMap == null) {
			criteriaListMap = new HashMap<>(this.relationManyToManyAggrStructList.size());
		}
		for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Set<Object> masterIdSet = resultList.stream()
				.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
				.filter(Objects::nonNull)
				.collect(toSet());
			if (CollectionUtils.isEmpty(masterIdSet)) {
				continue;
			}
			RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation;
			// 提取关联中用到的各种字段和表数据。
			BasicAggregationRelationInfo basicRelationInfo =
				this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap);
			// 构建多表关联的where语句
			StringBuilder whereClause = new StringBuilder(256);
			// 如果需要从表聚合计算或参与过滤，则需要把中间表和从表之间的关联条件加上。
			if (!basicRelationInfo.onlySelectRelationTable) {
				whereClause.append(basicRelationInfo.relationTable)
					.append(".")
					.append(basicRelationInfo.relationSlaveColumn)
					.append(" = ")
					.append(basicRelationInfo.slaveTable)
					.append(".")
					.append(basicRelationInfo.slaveColumn);
			} else {
				whereClause.append("1 = 1");
			}
			List<MyWhereCriteria> criteriaList = criteriaListMap.get(relationStruct.relationField.getName());
			if (criteriaList == null) {
				criteriaList = new LinkedList<>();
			}
			MyWhereCriteria inlistFilter = new MyWhereCriteria();
			inlistFilter.setCriteria(relation.relationModelClass(),
				relation.relationMasterIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet);
			criteriaList.add(inlistFilter);
			if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) {
				MyWhereCriteria deleteFilter = new MyWhereCriteria();
				deleteFilter.setCriteria(
					relation.slaveModelClass(),
					relationStruct.service.deletedFlagFieldName,
					MyWhereCriteria.OPERATOR_EQUAL,
					SysConstant.STATUS_NORMAL);
				criteriaList.add(deleteFilter);
			}
			String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList);
			whereClause.append(AND_OP).append(criteriaString);
			StringBuilder tableNames = new StringBuilder(64);
			tableNames.append(basicRelationInfo.relationTable);
			if (!basicRelationInfo.onlySelectRelationTable) {
				tableNames.append(", ").append(basicRelationInfo.slaveTable);
			}
			List<Map<String, Object>> aggregationMapList =
				super.getBaseMapper().getGroupedListByCondition(tableNames.toString(),
					basicRelationInfo.selectList, whereClause.toString(), basicRelationInfo.groupBy);
			doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct);
		}
	}

	private void doMakeLocalAggregationData(
		List<Map<String, Object>> aggregationMapList, List<T> resultList, RelationStruct relationStruct) {
		if (CollectionUtils.isEmpty(resultList)) {
			return;
		}
		// 根据获取的分组聚合结果集，绑定到主表总的关联字段。
		if (CollectionUtils.isNotEmpty(aggregationMapList)) {
			Map<Object, Object> relatedMap = new HashMap<>(aggregationMapList.size());
			for (Map<String, Object> map : aggregationMapList) {
				relatedMap.put(map.get(GROUPED_KEY), map.get(AGGREGATED_VALUE));
			}
			for (T dataObject : resultList) {
				Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
				if (masterIdValue != null) {
					Object value = relatedMap.get(masterIdValue);
					if (value != null) {
						ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
					}
				}
			}
		}
	}

	/**
	 * 根据实体对象参数列表和过滤条件，集成本地一对多关联聚合计算数据。
	 *
	 * @param resultList      实体对象数据列表。
	 * @param criteriaListMap 过滤参数。key为主表字段名称，value是过滤条件列表。
	 * @param ignoreFields    该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	private void buildOneToManyAggregationForDataList(
		List<T> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
		// 处理多一多场景下，根据主表的结果，进行从表聚合数据的计算。
		if (CollectionUtils.isEmpty(this.relationOneToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
			return;
		}
		if (criteriaListMap == null) {
			criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size());
		}
		for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) {
			if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
				continue;
			}
			Set<Object> masterIdSet = resultList.stream()
				.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
				.filter(Objects::nonNull)
				.collect(toSet());
			if (CollectionUtils.isEmpty(masterIdSet)) {
				continue;
			}
			RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation;
			// 开始获取后面所需的各种关联数据。此部分今后可以移植到缓存中，无需每次计算。
			String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass());
			String slaveColumnName = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass());
			Tuple2<String, String> selectAndGroupByTuple = makeSelectListAndGroupByClause(
				slaveTable, slaveColumnName, relation.slaveModelClass(),
				slaveTable, relation.aggregationField(), relation.aggregationType());
			String selectList = selectAndGroupByTuple.getFirst();
			String groupBy = selectAndGroupByTuple.getSecond();
			List<MyWhereCriteria> criteriaList = criteriaListMap.get(relationStruct.relationField.getName());
			if (criteriaList == null) {
				criteriaList = new LinkedList<>();
			}
			MyWhereCriteria inlistFilter = new MyWhereCriteria();
			inlistFilter.setCriteria(relation.slaveModelClass(),
				relation.slaveIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet);
			criteriaList.add(inlistFilter);
			if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) {
				MyWhereCriteria deleteFilter = new MyWhereCriteria();
				deleteFilter.setCriteria(
					relation.slaveModelClass(),
					relationStruct.service.deletedFlagFieldName,
					MyWhereCriteria.OPERATOR_EQUAL,
					SysConstant.STATUS_NORMAL);
				criteriaList.add(deleteFilter);
			}
			String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList);
			List<Map<String, Object>> aggregationMapList =
				super.getBaseMapper().getGroupedListByCondition(slaveTable, selectList, criteriaString, groupBy);
			doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct);
		}
	}

	/**
	 * 判断参数值主键集合中的所有数据，是否全部存在
	 *
	 * @param idSet  待校验的主键集合。
	 * @return 全部存在返回true，否则false。
	 */
	@Override
	public boolean existAllPrimaryKeys(Set<Long> idSet) {
		if (CollectionUtils.isEmpty(idSet)) {
			return true;
		}
		return this.existUniqueKeyList(idFieldName, idSet);
	}

	/**
	 * 判断参数值列表中的所有数据，是否全部存在。另外，keyName字段在数据表中必须是唯一键值，否则返回结果会出现误判。
	 *
	 * @param inFilterField  待校验的数据字段，这里使用Java对象中的属性，如courseId，而不是数据字段名course_id
	 * @param inFilterValues 数据值列表。
	 * @return 全部存在返回true，否则false。
	 */
	@Override
	public <K> boolean existUniqueKeyList(String inFilterField, Set<K> inFilterValues) {
		if (CollectionUtils.isEmpty(inFilterValues)) {
			return true;
		}
		String column = this.safeMapToColumnName(inFilterField);
		return super.getBaseMapper().selectCount(new QueryWrapper<T>().in(column, inFilterValues)) == inFilterValues.size();
	}

	static class RelationStruct {
		private Field relationField;
		private Field masterIdField;
		private Field equalOneToOneRelationField;
		private BaseServiceImpl<BaseDaoMapper<BaseEntity>, BaseEntity> service;
		private BaseMapper<Object> manyToManyMapper;
		private Map<Object, String> dictMap;
		private RelationDict relationDict;
		private RelationOneToOne relationOneToOne;
		private RelationOneToMany relationOneToMany;
		private RelationManyToMany relationManyToMany;
		private RelationOneToManyAggregation relationOneToManyAggregation;
		private RelationManyToManyAggregation relationManyToManyAggregation;
	}

	private static class BasicAggregationRelationInfo {
		private String slaveTable;
		private String slaveColumn;
		private String relationTable;
		private String relationMasterColumn;
		private String relationSlaveColumn;
		private String selectList;
		private String groupBy;
		private boolean onlySelectRelationTable;
	}
}
